package controllers

import javax.inject.Inject

import common.LoggerComponent
import exceptions._
import models.SToken
import play.api.libs.json.Json.JsValueWrapper
import play.api.libs.json._
import play.api.mvc._
import repos.UserRepository

import scala.concurrent.Future
import scala.util.Try

class BaseController @Inject()() extends Controller with LoggerComponent {

  import scala.concurrent.ExecutionContext.Implicits.global


//  implicit def dateJodaFormat = Reads.jodaDateReads("")
  var JSON_UTF8 = JSON + "; charset=utf8"

  @Inject()
  private var userRepository: UserRepository = _

  /**
    * simple cors response
    *
    * @param path
    * @return
    */
  def cors(path: String) = Action.async {
    Future.successful(Ok(Json.obj()).withHeaders(
      ("Access-Control-Allow-Origin", "*"),
      ("Access-Control-Allow-Method", "POST,PUT,PATCH,DELETE"),
      ("Access-Control-Allow-Headers", "X-Requested-With,Content-Type")
    )
    )
  }

  type RoleStr = String
  type Roles = Array[String]


  def authJsonAction[A](roles: Roles)(block: (A, Request[JsValue]) => Future[Map[String, JsValueWrapper]])(implicit jsonReads: Reads[A], jsonWrites: Writes[A]): Action[JsValue] = Action.async(parse.json) {
    implicit request =>
      println("================================request.body = " + request.body)
      Try {
        request.headers.get("userKey") match {
          case Some(key) =>
            val oProfile = userRepository.getProfile(key)
            //            println("--"*13+oProfile+"--"*13)
            oProfile match {
              case Some(profile) =>
                if (profile.roles.count(r => {
                  println("roles = " + roles + ", roleCode = " + r.roleCode)
                  roles.contains(r.roleCode)
                }) > 0) {
                  //                  println("==" * 13+request.body+"=="*13)
                  request.body.validate[A].fold(
                    errors => {
                      throw new HttpParamsParseError(errors)
                    },
                    param => {
                      block(param, request).map(retMap => {
                        val rst = for ((k, v) <- retMap)
                          yield Json.obj(k -> v)
                        Ok(rst.reduce(_ ++ _)).as(JSON_UTF8)
                      })
                    }
                  )
                }
                else
                  throw new AuthErrorNoJurisdiction
              case None =>
                throw new UnLoginError
            }
          case None =>
            throw new UnLoginError
        }
      }.recover(recoverHandler).get
  }

  def tokenJsonAction[A](block: (A, Request[JsValue]) => Future[Map[String, JsValueWrapper]])(implicit jsonReads: Reads[A], jsonWrites: Writes[A]): Action[JsValue] = Action.async(parse.json) {
    implicit request =>
      println("================================request.body = " + request.body)
      Try {
        request.headers.get("Play-Auth-Key") match {
          case Some(key) =>
            //            验证TOKEN
            if (SToken.validate(key)) {
              request.body.validate[A].fold(
                errors => {
                  throw new HttpParamsParseError(errors)
                },
                param => {

                  block(param, request).map(retMap => {
                    val rst = for ((k, v) <- retMap)
                      yield Json.obj(k -> v)
                    Ok(rst.reduce(_ ++ _)).as(JSON_UTF8)
                  })
                }
              )
            }
            else
              throw new AuthErrorNoJurisdiction
          case None =>
            throw new UnLoginError
        }
      }.recover(recoverHandler).get
  }

  def jsonAction[A](block: (A, Request[JsValue]) => Future[Map[String, JsValueWrapper]])(implicit jsonReads: Reads[A], jsonWrites: Writes[A]) =
    Action.async(parse.json) {
      implicit request =>
        println("================================= request.body = " + request.body)
        Try {
          request.body.validate[A].fold(
            errors => {
              throw new HttpParamsParseError(errors)
            },
            param => {
              block(param, request).map(ret => {
                Ok((for {(k, v) <- ret} yield Json.obj(k -> v)).reduce(_ ++ _)).as(JSON_UTF8)
              })
            }
          )
        }.recover(recoverHandler).get
    }

  def recoverHandler: PartialFunction[Throwable, Future[Result]] = {
    case e: HttpParamsParseError =>
      log.error(e.errorMsg)
      log.debug(e.errorMsg, e.fillInStackTrace())

      Future.successful(Ok(Json.obj("success" -> false,
        "resultCode" -> e.errorNo,
        "message" -> e.errorMsg,
        "errors" -> JsError.toJson(e.errors))).as(JSON_UTF8))
    case e: BusinessException =>
      log.error(e.errorMsg)
      log.debug(e.errorMsg, e.fillInStackTrace())
      Future.successful(Ok(Json.obj("success" -> false,
        "resultCode" -> e.errorNo,
        "message" -> e.errorMsg
      )).as(JSON_UTF8))
    case e: Exception =>
      log.error(e.toString)
      log.debug(e.toString, e.fillInStackTrace())
      throw e
  }

}
